import asyncio
import json
import uuid
from typing import AsyncGenerator, Dict, List
from fastapi import FastAPI
from fastapi import APIRouter, Request, HTTPException, Header
from fastapi.responses import StreamingResponse

from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse
from common.logger import logger
from conf.config import settings
from schemas.user import UserToken

from agents.class_agent import LangGraphMCPAgent
from conf.config import settings



test_router = APIRouter()

# 先获取完整响应，然后再流式返回
async def chat_stream(
        messages: List[Dict[str, str]], 
        sessionid: str, 
        app: FastAPI,
        model_name: str,
        is_thinking: bool, 
        online_search: bool
    ) -> AsyncGenerator[str, None]:

    print(model_name)
    logger.info(f"开始流式聊天，消息数量: {len(messages)}")
    
    # 初始化 reasoning_content 变量
    reasoning_content = ""
    
    try:
        start_time = asyncio.get_event_loop().time()
        logger.info("开始调用LangGraph处理请求")
        lg = LangGraphMCPAgent(
            model_name=model_name, 
            is_thinking=is_thinking, 
            online_search=online_search, 
            app=app
            )
        graph = await lg.initialize()
        config = {"configurable": {"thread_id": sessionid}}
        logger.info(config)
        async for event in graph.astream(
            {"messages": messages},
            config,
            stream_mode="messages"
        ):

            
            # 获取结果内容
            ai_message = event[0]

            
            # 安全地获取 reasoning_content
            reasoning_content = ai_message.additional_kwargs.get("reasoning_content", "")
            response = ai_message.content

            # print(response, len(response))

            if len(response) > 15:
                response = ""


            response_metadata = event[0].response_metadata
            if response_metadata == "stop":
                yield "data: [DONE]\n\n"


            # 设置分块参数
            data = {
                    "choices": [
                        {
                            "delta": {
                                "content": response,
                                "reasoning_content": reasoning_content
                            }
                        }
                    ]
                }
            # logger.info(data)
            yield f"data: {json.dumps(data, ensure_ascii=False)}\n\n"
            end_time = asyncio.get_event_loop().time()
        logger.info(f"LangGraph 执行完成，耗时: {end_time - start_time:.2f}秒")

        

    except Exception as e:
        error_data = {
            "choices": [
                {
                    "delta": {
                        "content": f"抱歉，发生了错误: {str(e)}",
                        "reasoning_content": reasoning_content
                    }
                }
            ]
        }
        logger.error(f"流式聊天出错: {str(e)}", exc_info=True)
        yield f"data: {json.dumps(error_data, ensure_ascii=False)}\n\n"
        yield "data: [DONE]\n\n"



@test_router.post("/completions", summary="聊天", description="聊天接口")
async def completions(request: Request):
    try:
        token = request.headers.get("token")
        logger.info(f"token: {token}")
        body = await request.json()

        model_name = body.get("model", "qwen3")
        is_thinking = body.get("is_thinking", False)
        messages = body.get("messages", [])
        sessionid = body.get("sessionid", "")
        requestid = body.get("requestid", "")
        online_search = body.get("online_search", False)
        stream = body.get("stream", True)  # 默认使用流式响应
        logger.info(f"用户输入的内容{messages}")

        app = request.app
        
        try:
            content = messages[0]["content"]
            redis = request.app.state.redis
            user_data = await redis.get(token)
            user_data = json.loads(user_data)
            logger.info(f"user_data: {user_data}")
            username = user_data["username"]
            replace_content = content + f";当前用户id为:{username};"
            messages[0]["content"] = replace_content
            logger.info(f"重新赋值后的内容{messages}")




        except Exception as e:
            logger.error(f"从Redis获取数据失败: {str(e)}", exc_info=True)

        # 确保消息格式正确
        if not messages or not isinstance(messages, list):
            logger.warning("消息格式不正确")
            return {"error": "消息格式不正确"}
        
        # 打印最后一条消息内容（调试用）
        if messages:
            last_msg = messages[-1]
            logger.info(f"最后一条消息: {last_msg.get('role', 'unknown')}: {last_msg.get('content', '')[:50]}...")
        
        # 返回流式响应
        return StreamingResponse(
            chat_stream(messages, sessionid, app, model_name, is_thinking, online_search), 
            media_type="text/event-stream",
            headers={
                "Cache-Control": "no-cache",
                "Connection": "keep-alive",
                "X-Accel-Buffering": "no",
                "Content-Type": "text/event-stream; charset=utf-8"
            }
        )
    except Exception as e:
        logger.error(f"处理聊天请求时出错: {str(e)}", exc_info=True)
        return {"error": f"处理请求时出错: {str(e)}"}


@test_router.get("/login", response_class=HTMLResponse)
async def login(request: Request):
    logger.info("进入登录页面")
    api_base_url = f"{settings.BASE_URL}:{settings.WEB_PORT}" 
    templates = Jinja2Templates(directory="templates")
    
    return templates.TemplateResponse("login.html", {"request": request, "api_base_url": api_base_url})


@test_router.get("/chat", response_class=HTMLResponse)
async def index(request: Request):
    logger.info("调用聊天界面")
    
    # 获取URL参数，只获取用户名
    username = request.query_params.get("username", "")
    
    logger.info(f"接收到的用户名: {username}")
    
    # 如果用户名为空，返回登录失败信息
    if not username:
        logger.warning("用户名为空，重定向到登录页面")
        templates = Jinja2Templates(directory="templates")
        api_base_url = f"{settings.BASE_URL}:{settings.WEB_PORT}"
        return templates.TemplateResponse(
            "login.html", 
            {
                "request": request, 
                "api_base_url": api_base_url,
                "login_error": "登录失败，用户名不能为空"
            }
        )
    
    templates = Jinja2Templates(directory="templates")
    api_base_url = f"{settings.BASE_URL}:{settings.WEB_PORT}" 
    logger.info(f"API基础URL: {api_base_url}")

    redis = request.app.state.redis
    token = str(uuid.uuid4().hex)
    print(f"生成的token: {token}")
    await redis.set(token, json.dumps({"username": username}), ex=60 * 60 * 24 * 7)
    
    # 只将用户名和API基础URL传递给模板，不传递密码
    return templates.TemplateResponse(
        "chat.html", 
        {
            "request": request, 
            "api_base_url": api_base_url,
            "username": username,
            "token": token
        }
    )





@test_router.get("/redis/get/{access_token}", summary="通过access_token获取user_id", response_model=Dict[str, str])
async def test_redis_get(request: Request, access_token: str) -> Dict[str, str]:
    try:
        # 获取 Redis 客户端
        redis = request.app.state.redis
        if not redis:
            logger.error("Redis 客户端未初始化")
            raise HTTPException(status_code=500, detail="Redis 服务不可用")
            
        # 从 Redis 获取数据
        user_data = await redis.get(access_token)
        if not user_data:
            logger.warning(f"未找到对应的access_token: {access_token}")
            raise HTTPException(status_code=404, detail="未找到对应的用户信息")
            
        # 将�JSON字符串转换回字典
        try:
            user_dict = json.loads(user_data)
            user_id = user_dict.get("user_id", "")
            logger.info(f"成功获取用户信息: access_token={access_token}, user_id={user_id}")
            return {"user_id": user_id, "access_token": access_token}
        except json.JSONDecodeError as e:
            logger.error(f"JSON解析失败: {str(e)}")
            raise HTTPException(status_code=500, detail="用户数据格式错误")
    except HTTPException:
        raise
    except Exception as e:
        error_msg = f"Redis 操作失败: {str(e)}"
        logger.error(error_msg, exc_info=True)
        raise HTTPException(status_code=500, detail=error_msg)


@test_router.post("/redis/set", summary="向 Redis 存入 JSON 数据", response_model=Dict[str, str])
async def test_redis_set(request: Request, user_token: UserToken) -> Dict[str, str]:
    try:
        # 记录数据信息
        logger.info(f"准备存储 JSON 数据: {user_token.dict()}")
        
        # 获取 Redis 客户端
        redis = request.app.state.redis
        if not redis:
            logger.error("Redis 客户端未初始化")
            raise HTTPException(status_code=500, detail="Redis 服务不可用")
            
        # 将数据存入 Redis
        key = f"{user_token.access_token}"
        # 将字典转换为JSON字符串
        user_data = json.dumps(user_token.dict())
        res = await redis.set(key, user_data, ex=7200)
        return {"status": "success", "message": "数据已成功存储到Redis"}
    except Exception as e:
        error_msg = f"Redis 操作失败: {str(e)}"
        logger.error(error_msg, exc_info=True)
        raise HTTPException(status_code=500, detail=error_msg)



@test_router.post("/messages/{sessionid}", summary="通过session获取对话信息")
async def get_messages(request: Request, sessionid: str):
    try:
        lg = LangGraphMCPAgent(app=request.app)
        graph = await lg.initialize()
        config = {"configurable": {"thread_id": sessionid}}
        # 使用异步方法获取状态
        state = await graph.aget_state(config=config)
        msgs = state.values
        
        # 将消息转换为可序列化的JSON格式
        serialized_messages = []
        if "messages" in msgs and isinstance(msgs["messages"], list):
            for msg in msgs["messages"]:
                # 转换消息对象为字典
                if hasattr(msg, "__dict__"):
                    # 处理特殊对象
                    msg_dict = {
                        "type": msg.__class__.__name__,
                        "content": msg.content if hasattr(msg, "content") else "",
                        "id": msg.id if hasattr(msg, "id") else "",
                    }
                    # 添加额外属性
                    if hasattr(msg, "additional_kwargs") and msg.additional_kwargs:
                        msg_dict["additional_kwargs"] = msg.additional_kwargs
                    if hasattr(msg, "response_metadata") and msg.response_metadata:
                        msg_dict["response_metadata"] = msg.response_metadata
                    
                    serialized_messages.append(msg_dict)
                else:
                    # 如果不是对象，尝试直接添加
                    serialized_messages.append(str(msg))
        
        return {"messages": serialized_messages}
    except Exception as e:
        logger.error(f"获取消息时出错: {str(e)}", exc_info=True)
        return {"error": f"获取消息时出错: {str(e)}"}

@test_router.post("/messages/{sessionid}", summary="通过session获取对话信息")
async def get_messages(request: Request, sessionid: str):



    return {"messages": []}